// *****************************************************************************
// CHANGE LOG
//
// *****************************************************************************

#include <p32xxxx.h>
#include <plib.h>
#include "Crc.h"

/*! \brief Creates a new instance of the CRC class
 */
Crc::Crc() { }

/*! \brief Default destructor
 */
Crc::~Crc() { }

/*! \brief Calculates the 16-bit CRC of the given data.
 *
 * @param data
 * @param length
 * @returns Calculated 16-bit CRC
 */
UINT16 Crc::CalculateModbus(const void *data, UINT32 length)
{
	UINT16 result;
	UINT8 *buffer;
	// Need to right-zero pad data
	buffer = (UINT8 *)malloc(length + 2);
	memcpy(buffer, data, length);
	buffer[length + 0] = 0;
	buffer[length + 1] = 0;

	// Calculate CRC using DMA module
	DmaSfmTxferReorder(0);
	DmaSfmConfigure(DMA_CHKSUM_CRC, DMA_BITO_LSb, DMA_REORDER_NOT);
	DmaSfmCrcConfigure(0x8005, 16, 0xEAA8);
	DmaChnMemCrc(&result, buffer, length + 2 , DMA_CHANNEL0 , DMA_CHN_PRI0);

	// No longer need temporary buffer
	free(buffer);

	// Bit reverse result (MSB->LSB)
	UINT8 low = result & 0xFF;
	UINT8 high = (result & 0xFF00) >> 8;
	low = ((low * 0x0802LU & 0x22110LU) | (low * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
	high = ((high * 0x0802LU & 0x22110LU) | (high * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;

	// Reverse Bytes
	result = (low << 8) | high;
	return result;
	
}
